package com.ele.client.lessons;

import com.ele.client.Presenter;
import com.ele.client.rpc.ApplicationServiceAsync;
import com.ele.client.rpc.SimpleAsyncCallback;
import com.ele.shared.dto.grid.SectionGridRow;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.DataGrid;
import com.github.gwtbootstrap.client.ui.NavLink;
import com.github.gwtbootstrap.client.ui.Pagination;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.*;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.*;

import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ListPresenter implements Presenter {

    public interface Display {
        Widget asWidget();

        Pagination getDataGridPagination();

        DataGrid getDataGrid();

        Button getAddButton();

        Button getDeleteButton();
    }

    private final ApplicationServiceAsync rpcService;
    private final HandlerManager eventBus;
    private final Display display;

    SimplePager dataGridPager = new SimplePager();
    private final MultiSelectionModel<SectionGridRow> selectionModel;
    ListDataProvider<SectionGridRow> dataProvider = new ListDataProvider<SectionGridRow>();

    public ListPresenter(ApplicationServiceAsync rpcService, HandlerManager eventBus, final Display display) {
        this.rpcService = rpcService;
        this.eventBus = eventBus;
        this.display = display;

        selectionModel = new MultiSelectionModel<SectionGridRow>();
        display.getDataGrid().setSelectionModel(selectionModel, DefaultSelectionEventManager.<SectionGridRow>createCheckboxManager());
    }

    private void bind() {
        display.getDeleteButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                Set<Long> set = new HashSet<Long>();
                for (SectionGridRow row : selectionModel.getSelectedSet()) {
                    set.add(row.getId());
                }

                rpcService.deleteLessons(set, new SimpleAsyncCallback<Void>() {
                    @Override
                    public void onSuccess(Void result) {
                        loadData();
                    }
                });
            }
        });
    }

    public void go(final HasWidgets container) {
        loadData();
        initTable(display.getDataGrid(), dataGridPager, display.getDataGridPagination());

        bind();
        container.clear();
        container.add(display.asWidget());
    }

    private void loadData() {
        rpcService.getLessonGridData(new SimpleAsyncCallback<List<SectionGridRow>>() {
            @Override
            public void onSuccess(List<SectionGridRow> rows) {
                dataProvider.setList(rows);
                rebuildPager(display.getDataGridPagination(), dataGridPager);
            }
        });
    }

    private void initTable(AbstractCellTable<SectionGridRow> table,final SimplePager pager,final Pagination pagination) {
        table.setEmptyTableWidget(new Label("Please add data."));

        Column<SectionGridRow, Boolean> checkColumn =
                new Column<SectionGridRow, Boolean>(new CheckboxCell(true, false)) {
                    @Override
                    public Boolean getValue(SectionGridRow object) {
                        // Get the value from the selection model.
                        return selectionModel.isSelected(object);
                    }
                };
        table.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
        table.setColumnWidth(checkColumn, 40, Style.Unit.PX);

        addIdColumn(table);
        addNameColumn(table);

        table.addRangeChangeHandler(new RangeChangeEvent.Handler() {

            @Override
            public void onRangeChange(RangeChangeEvent event) {
                rebuildPager(pagination, pager);
            }
        });
        pager.setDisplay(table);
        pagination.clear();

        dataProvider.addDataDisplay(table);
    }

    private void addNameColumn(AbstractCellTable<SectionGridRow> table) {
        TextColumn<SectionGridRow> lessonNameCol = new TextColumn<SectionGridRow>() {
            @Override
            public String getValue(SectionGridRow object) {
                return object.getName();
            }

            @Override
            public void render(Cell.Context context, SectionGridRow object, SafeHtmlBuilder sb) {
                sb.appendHtmlConstant("<a href=\"#action=editor&id=" + object.getId() + "\">");
                sb.appendEscaped(object.getName());
                sb.appendHtmlConstant("</a>");
            }
        };
        lessonNameCol.setSortable(true);
        table.addColumn(lessonNameCol, "Name");
        ColumnSortEvent.ListHandler<SectionGridRow> lessonNameColHandler = new ColumnSortEvent.ListHandler<SectionGridRow>(dataProvider.getList());
        lessonNameColHandler.setComparator(lessonNameCol, new Comparator<SectionGridRow>() {
            @Override
            public int compare(SectionGridRow o1, SectionGridRow o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        table.addColumnSortHandler(lessonNameColHandler);
    }

    private void addIdColumn(AbstractCellTable<SectionGridRow> table) {
        TextColumn<SectionGridRow> idCol = new TextColumn<SectionGridRow>() {
            @Override
            public String getValue(SectionGridRow object) {
                return String.valueOf(object.getId());
            }
        };
        idCol.setSortable(true);
        table.setColumnWidth(idCol, 40, Style.Unit.PX);
        table.addColumn(idCol, "#");
        ColumnSortEvent.ListHandler<SectionGridRow> idColHandler = new ColumnSortEvent.ListHandler<SectionGridRow>(dataProvider.getList());
        idColHandler.setComparator(idCol, new Comparator<SectionGridRow>() {
            @Override
            public int compare(SectionGridRow o1, SectionGridRow o2) {
                return o1.getId().compareTo(o2.getId());
            }
        });
        table.addColumnSortHandler(idColHandler);
        table.getColumnSortList().push(idCol);
    }

    private void rebuildPager(final Pagination pagination,final SimplePager pager) {
        pagination.clear();

        if (pager.getPageCount() == 0) {
            return;
        }

        NavLink prev = new NavLink("<");

        prev.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                GWT.log(String.valueOf("prev"));
                pager.previousPage();
            }
        });

        prev.setDisabled(!pager.hasPreviousPage());

        pagination.add(prev);

        int before = 2;
        int after = 2;

        while (!pager.hasPreviousPages(before) && before > 0) {
            before--;
            if(pager.hasNextPages(after + 1)) {
                after++;
            }
        }


        while (!pager.hasNextPages(after) && after > 0) {
            after--;
            if(pager.hasPreviousPages(before+1)) {
                before++;
            }
        }

        for (int i = pager.getPage() - before; i <= pager.getPage() + after; i++) {

            final int index = i + 1;

            NavLink page = new NavLink(String.valueOf(index));

            page.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(ClickEvent event) {
                    pager.setPage(index - 1);
                }
            });

            if (i == pager.getPage()) {
                page.setActive(true);
            }

            pagination.add(page);
        }

        NavLink next = new NavLink(">");

        next.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                GWT.log(String.valueOf("next"));
                pager.nextPage();
            }
        });

        next.setDisabled(!pager.hasNextPage());

        pagination.add(next);
    }
}
